package com.gientech.madp.sm2.service.impl;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.gientech.madp.sm2.service.SM2Service;
import com.gientech.madp.sm2.utils.FopJsonUtil;
import com.gientech.madp.sm2.utils.R;
import com.gientech.madp.sm2.utils.SM2Util;
import lombok.AllArgsConstructor;
import org.apache.commons.lang.StringUtils;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.encoders.Hex;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author smile_ZhongXuan
 * @Date 2021/10/9 14:22
 * @Version 1.0
 */
@Service
@AllArgsConstructor
public class SM2ServiceImpl implements SM2Service {

	@Override
	public R generateKey() {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Map map = new HashMap<>();
		try {
			AsymmetricCipherKeyPair asymmetricCipherKeyPair = SM2Util.generateKeyPair();
			ECPoint ecPoint = ((ECPublicKeyParameters)asymmetricCipherKeyPair.getPublic()).getQ();
			String publicKey = Hex.toHexString(ecPoint.getEncoded(false));
			String privateKey = ((ECPrivateKeyParameters)asymmetricCipherKeyPair.getPrivate()).getD().toString(16);
			map.put("publicKey",publicKey);
			map.put("privateKey",privateKey);
		}
		catch (Exception e) {
			return R.failed(sdf.format(new Date())+ ": 生成秘钥失败!");
		}
		return R.ok(map,"生成的SM2公钥和私钥");
	}

	@Override
	public R counterSign(String privateKey, Map map) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		if (StringUtils.isBlank(privateKey)) {
			return R.failed(sdf.format(new Date()) + ": 私钥不能为空。");
		}
		if(map.isEmpty()) {
			return R.failed(sdf.format(new Date()) + ": 加签报文不能为空。");
		}
		map.remove("sign");
		String signContent = FopJsonUtil.getSignContents(map);
		System.out.println("加签signContent：" + signContent);
		String sign = null;
		try {
			sign = SM2Util.sign(signContent, privateKey);
		} catch (Exception e) {
			return R.failed(sdf.format(new Date()) + ": 加签出现异常：" + e.getMessage());
		}
		return R.ok(sign,sdf.format(new Date()) + ": 加签后签名字符串");
	}

	@Override
	public R verifySignature(String publicKey, Map map) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		if (StringUtils.isBlank(publicKey)) {
			return R.failed(sdf.format(new Date()) + ": 公钥不能为空。");
		}
		if (map.isEmpty()) {
			return R.failed(sdf.format(new Date()) + ": 验签报文不能为空。");
		}
		Map<String,String> sign = (Map<String, String>) map.get("sign");
		String signature = sign.get("signature");
		map.remove("sign");
		boolean result = false;
		String signContent = FopJsonUtil.getSignContents(map);
		System.out.println("验签signContent：" + signContent);
		try {
			result = SM2Util.verify(signContent, publicKey, signature);
		} catch (Exception e) {
			return R.failed(sdf.format(new Date()) + ": 验签出现异常：" + e.getMessage());
		}
		if (result) {
			return R.ok(sdf.format(new Date()) + "：签名验证成功！","验签成功");
		}
		return R.failed(sdf.format(new Date()) + "：签名验证失败！","验签失败");
	}

	@Override
	public R verificationKey(String privateKey, String publicKey) {
		privateKey = StringUtils.replace(privateKey, "\n", "");
		privateKey = StringUtils.replace(privateKey, "\r", "");
		publicKey = StringUtils.replace(publicKey, "\n", "");
		publicKey = StringUtils.replace(publicKey, "\r", "");
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		if (StringUtils.isBlank(privateKey)) {
			return R.failed(sdf.format(new Date()) + ": 私钥不能为空。");
		}
		if (StringUtils.isBlank(publicKey)) {
			return R.failed(sdf.format(new Date()) + ": 公钥不能为空。");
		}
		boolean result = false;
		try {
			result = SM2Util.match(publicKey, privateKey);
		} catch (Exception e) {
			return R.failed(sdf.format(new Date()) + "：秘钥对匹配失败！","秘钥校验失败");
		}
		if (result) {
			return R.ok(sdf.format(new Date()) + "：秘钥对匹配成功！","秘钥校验成功");
		}
		return R.failed(sdf.format(new Date()) + "：秘钥对匹配失败！","秘钥校验失败");
	}

	@Override
	public R encrypt(String publicKey, Map map) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		JSONObject content = JSONUtil.parseObj(map);
		if(StringUtils.isBlank(publicKey)) {
			return R.failed(sdf.format(new Date()) + ": 公钥不能为空。");
		}
		if(content.isEmpty()) {
			return R.failed(sdf.format(new Date()) + ": 加密报文不能为空。");
		}
		String encrypt = null;
		try {
			encrypt = SM2Util.encrypt(publicKey, content.toString());
			System.out.println("加密： " + encrypt);
		} catch (InvalidCipherTextException e) {
			e.printStackTrace();
		}
		return R.ok(encrypt,"加密后的报文。");
	}

	@Override
	public R decrypt(String privateKey, Map map) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String enString = map.get("enString").toString();
		if(StringUtils.isBlank(privateKey)) {
			return R.failed(sdf.format(new Date()) + ": 私钥不能为空。");
		}
		if(StringUtils.isBlank(enString)) {
			return R.failed(sdf.format(new Date()) + ": 加密后的报文不能为空。");
		}
		String decrypt = null;
		try {
			decrypt = SM2Util.decrypt(privateKey, enString);
			System.out.println("解密： " + JSONUtil.parseObj(decrypt));
		} catch (InvalidCipherTextException e) {
			e.printStackTrace();
		}
		return R.ok(JSONUtil.parseObj(decrypt),"解密后的报文。");
	}
}